package com.oauth.client.config;

import com.oauth.client.MyUserInfoTokenServices;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2019/9/16.
 */
//@EnableOAuth2Sso
//@EnableWebSecurity
@EnableOAuth2Client
@Configuration
@Slf4j
public class OauthSercurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private OAuth2ClientContext oauth2ClientContext;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //.requestMatchers()
                //.antMatcher("/**")
                //.and()
                .authorizeRequests()
                .antMatchers("/login**", "/webjars/**").permitAll()
                .anyRequest().authenticated().and().exceptionHandling()
                .and()
                .logout().
                logoutUrl("/logout").
                logoutSuccessUrl("/")
                .and()
                //.oauth2Login().and()
                //.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .csrf().disable()
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
        //http.addFilterBefore(tokenAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    private Filter ssoFilter() {
        OAuth2ClientAuthenticationProcessingFilter oauth2Filter = new OAuth2ClientAuthenticationProcessingFilter("/login");
        OAuth2RestTemplate oauth2Template = new OAuth2RestTemplate(github(), oauth2ClientContext);
        oauth2Filter.setRestTemplate(oauth2Template);

        /*AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider();
        authCodeProvider.setStateMandatory(false);
        AccessTokenProviderChain provider = new AccessTokenProviderChain(
                Arrays.asList(authCodeProvider));
        oauth2Template.setAccessTokenProvider(authCodeProvider);*/
        UserInfoTokenServices userInfoTokenServices = new MyUserInfoTokenServices(githubResource().getUserInfoUri(), github().getClientId());
        userInfoTokenServices.setRestTemplate(oauth2Template);
        userInfoTokenServices.setAuthoritiesExtractor(new AuthoritiesExtractor() {
            @Override
            public List<GrantedAuthority> extractAuthorities(Map<String, Object> map) {
                log.info("====> {}", map);
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority("guest");
                List<GrantedAuthority> res = new ArrayList<>();
                res.add(authority);
                return res;
            }
        });
        oauth2Filter.setTokenServices(userInfoTokenServices);
        return oauth2Filter;
    }

    @Bean
    public FilterRegistrationBean oauth2ClientFilterRegistration(
            OAuth2ClientContextFilter filter) {
        log.info("====> 初始化");
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(filter);
        registration.setOrder(-100);
        return registration;
    }

    @Bean
    @ConfigurationProperties("oauth2.client")
    public AuthorizationCodeResourceDetails github() {
        return new AuthorizationCodeResourceDetails();
    }

    @Bean
    @ConfigurationProperties("oauth2.resource")
    public ResourceServerProperties githubResource() {
        return new ResourceServerProperties();
    }
}
